#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <asm/uaccess.h>

#define NAME "beep"

int major = 602; //定义主设备号的变量
unsigned int * gpioc14_fn;
unsigned int * pwm_base;
int kbuf[3] = {0};
//kbuf[0]  1  开启蜂鸣器 0关闭蜂鸣器
//kbuf[1]  周期的值
//kbuf[2]  占空比的值

int beep_open(struct inode *inode, struct file *file)
{
	return 0;	
}

ssize_t beep_read(struct file *file, char __user * ubuf, 
		size_t size, loff_t *offs)
{
	return 0;
}
ssize_t beep_write(struct file *file, const char __user *ubuf,
		size_t size, loff_t *offs)
{
	int ret;

	//1接受用户空间传递的周期起占空比
	if(size > sizeof(kbuf)) size = sizeof(kbuf);
	ret = copy_from_user(kbuf,ubuf,size);
	if(ret){
		printk("copy data to user error");
		return -EIO;
	}
	//2.判断用户是想开始或关闭蜂鸣器
	if(kbuf[0] == 0){
		//关闭蜂鸣器
		*(pwm_base + 9) = 0; //周期
		*(pwm_base + 10) = 0;//占空比
		*(pwm_base + 2) &= ~(0xf<<12);//将tcon先清空
		*(pwm_base + 2) |= (0xb<<12); //启动蜂鸣器
		*(pwm_base + 2) &= ~(1<<13);  //将手动重装清掉
	}else{
		//开启蜂鸣器
		//3.将用户传递过来的值写到周期和占空比的寄存器中
		*(pwm_base + 9) = kbuf[1]; //周期
		*(pwm_base + 10) = kbuf[2];//占空比
		//4.启动蜂鸣器
		*(pwm_base + 2) &= ~(0xf<<12);//将tcon先清空
		*(pwm_base + 2) |= (0xb<<12); //启动蜂鸣器
		*(pwm_base + 2) &= ~(1<<13);  //将手动重装清掉
	}
	return size;	
}
int beep_close(struct inode *inode, struct file *file)
{
	return 0;	
}

struct file_operations fops = {
	.open    = beep_open,
	.read    = beep_read,
	.write   = beep_write,
	.release = beep_close,
};
//入口函数
static int  beep_init(void)
{
	int ret;
	printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
	//1.注册字符设备驱动
	ret = register_chrdev(major,NAME,&fops);
	if(ret < 0){
		printk("register char device error\n");
		return ret;
	}

	printk("beep major = %d\n",major);

	//2.将gpio和pwm的寄存器地址映射
	gpioc14_fn = ioremap(0xc001c020,4);
	if(gpioc14_fn == NULL){
		printk("gpioc14_fn ioremap error\n");
		return -ENOMEM;
	}

	pwm_base = ioremap(0xc0018000,44);
	if(pwm_base == NULL){
		printk("pwm_base ioremap error\n");
		return -ENOMEM;
	}

	//3.对寄存器初始化
	*gpioc14_fn &= ~(3<<28);	
	*gpioc14_fn |= (2<<28);	//设置为pwm模式
	*pwm_base &= ~(0xff<<8);
	*pwm_base |= (249<<8); //预分频器设置的值为249
	*(pwm_base + 1)&= ~(0xf<<8);
	*(pwm_base + 1)|= (3<<8);//设置分频器为8分频
	//关闭蜂鸣器
	*(pwm_base + 9) = 0; //周期
	*(pwm_base + 10) = 0;//占空比	
	*(pwm_base + 2) &= ~(0xf<<12);//将tcon先清空
	*(pwm_base + 2) |= (0xb<<12); //启动蜂鸣器
	*(pwm_base + 2) &= ~(1<<13);  //将手动重装清掉
	
	return 0;
}

//出口函数
static void beep_exit(void)
{
	printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
	//1.取消映射
	iounmap(gpioc14_fn);
	iounmap(pwm_base);
	//2.注销字符设备驱动
	unregister_chrdev(major,NAME);
}
module_init(beep_init);
module_exit(beep_exit);
MODULE_LICENSE("GPL"); //模块的许可证

